﻿/*
 * ======================================================================
 *                           Modern Warfare3 Launcher
 * Copyright 2011-2012
 * Developer:Pooya parsa
 * Email:pingsft@gmail.com
 * You are ALLOWED:
 * -Read source code
 * -Use some part of source code with Full name and email of developer
 * -Release your own mod with name of develepor
 * You are NOT ALLOWD:
 * -Add cracked version of Mw3
 * -Release modified version as MW3Launcher
 * -Mirror Sourcecode
 * -Use source code without name of developer
 * Thank you for your attention
 * ======================================================================
 * */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
//using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics;

namespace MW3Launcher
{
    public partial class Updater : UserControl
    {
        WebClient w;
        Operation_e _operation;
        Config _Config;
        
        public Operation_e Operation
        {
            get { return _operation; }
            set { _operation = value; StatusChanged(); }
        }
        string Err;
        File CurrentFile;
        List<File> Files;
        int TotalFiles;
        public delegate void Onstatuschange();
        public event Onstatuschange StatusChanged;


        public Updater()
        {
            InitializeComponent();
            StatusChanged += new Onstatuschange(Updater_StatusChanged);
            _Config = new Config();
            w = new WebClient();
            Operation = Operation_e.free;
          
        }

        void Updater_StatusChanged()
        {
            UpdateStatus();
        }

        public enum Operation_e
        {
            free, gettinglist, finished, downloading, error, copying,updatestarting
        }
        class File
        {
            public string Name;
            public string Md5;
            public int Size;
            public string sSize { get { return ((float)(Size / 1024) / 1000).ToString(); } }
            public bool UpdateNeeded;
            public File()
            {
                Size = 0;
            }
        }
        public void StartUpdate()
        {
            w = new WebClient();
            Operation = Operation_e.gettinglist;
            w.DownloadStringCompleted += new DownloadStringCompletedEventHandler(w_DownloadStringCompleted);
            w.DownloadFileCompleted += new AsyncCompletedEventHandler(w_DownloadFileCompleted);
            w.DownloadProgressChanged += new DownloadProgressChangedEventHandler(w_DownloadProgressChanged);
            w.DownloadStringAsync(new Uri(_Config.UpdateList));
            progressBar1.Style = ProgressBarStyle.Marquee;
            lblStatus2.Text = "";
        }

        void w_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

        void w_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Err = e.Error.Message;
                Operation = Operation_e.error;
                return;
            }
            Files = new List<File>();
            //Parse update data
            foreach (string f in e.Result.Split('\n'))
            {
                if (f == "" || f == "\r") break;
                File ff = new File();
                string[] s = f.Split('\t');
                ff.Name = s[0];
                ff.Md5 = s[1];
                ff.Size = Convert.ToInt32(s[2]);
                //Check on local
                ff.UpdateNeeded = true;
                if (System.IO.File.Exists(ff.Name))
                    if (GetMD5HashFromFile(ff.Name) == ff.Md5)
                        ff.UpdateNeeded = false;
                if (ff.UpdateNeeded) { Files.Add(ff); }
                TotalFiles = Files.Count;
            }
            if (Files.Count > 0) Operation = Operation_e.updatestarting;
            progressBar1.Style = ProgressBarStyle.Blocks;
            NextDownload();

        }

        public void NextDownload()
        {

            lblStatus2.Text = (TotalFiles - Files.Count).ToString() + " / " + TotalFiles.ToString() + " Files recieved";
            if (TotalFiles > 0) progressBar2.Value = ((TotalFiles - Files.Count) * 100) / (TotalFiles);
            if (Files.Count > 0)
            {
                CurrentFile = Files[0];
                Operation = Operation_e.downloading;
                //Exe fix
                w.DownloadFileAsync(new Uri(_Config.UpdateBaseUrl + CurrentFile.Name.Replace(".exe", "[dot]exe")), CurrentFile.Name + ".tmp");
            }
            else
            {
                Operation = Operation_e.finished;

            }
        }

        void w_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            //Exe fix
            string hash = GetMD5HashFromFile(CurrentFile.Name + ".tmp");
            if (hash == CurrentFile.Md5)
            {
                Operation = Operation_e.copying;
                //Try to kill exe
                try
                {
                    if(CurrentFile.Name.EndsWith("exe"))
                        KillExe(CurrentFile.Name);
                }
                catch { }
                try
                {
                    if (!Directory.Exists("Mw3LauncherBackups"))
                        Directory.CreateDirectory("Mw3LauncherBackups");
                    if (System.IO.File.Exists(CurrentFile.Name))
                        System.IO.File.Replace(CurrentFile.Name + ".tmp", CurrentFile.Name, @"Mw3LauncherBackups\" + CurrentFile.Name + ".bak-" + hash);
                    else
                        System.IO.File.Move(CurrentFile.Name + ".tmp", CurrentFile.Name);
                }
                catch { }
                Files.Remove(CurrentFile);
                NextDownload();
            }
            else
            {
                //TODO
                //Download broken
                //Skip it...
                Files.Remove(CurrentFile);
                NextDownload();
            }
        }

        void UpdateStatus()
        {
            switch (this.Operation)
            {
                case Operation_e.gettinglist:
                    lblStatus.Text = "Getting update ...";
                    break;
                case Operation_e.free:
                    lblStatus.Text = "Ready.";
                    break;
                case Operation_e.finished:
                    lblStatus.Text = "Update finished";
                    Environment.Exit(0);
                    break;
                case Operation_e.error:
                    lblStatus.Text = "Error: " + Err;
                    break;
                case Operation_e.downloading:
                    lblStatus.Text = "Downloading file: " + CurrentFile.Name + " (" + CurrentFile.sSize + " Mb)";
                    break;
                case Operation_e.copying:
                    lblStatus.Text = "Copy file: " + CurrentFile.Name + " (" + CurrentFile.sSize + " Mb)";
                    break;
            }
        }

        protected string GetMD5HashFromFile(string fileName)
        {
            if (!System.IO.File.Exists(fileName)) return "";
            FileStream inputStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            byte[] buffer = new MD5CryptoServiceProvider().ComputeHash(inputStream);
            inputStream.Close();
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < buffer.Length; i++)
            {
                builder.Append(buffer[i].ToString("x2"));
            }
            return builder.ToString();
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start(_Config.DownloadUrl);
        }
        private void KillExe(string name)
        {
            string solidname = name.Remove(name.Length - 4,4);
            foreach (Process p in System.Diagnostics.Process.GetProcessesByName(solidname))
                try { p.Kill(); }
                catch { }
        }


    }
}
